1. 死锁
- 进程和线程都会有死锁的现象
- 两个或两个以上的进程/线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程/线程称为死锁进程/线程
- 死锁的出行的情况: 在多线程并发的情况下,同一个线程中如果出现多次 acquire 就可能产生死锁线程现象
# 死锁的现象
from threading import Lock
lock = Lock()
lock.acquire() # 上锁
lock.acquire() # 在这里会一直等待解锁,因为上面已经上了一把锁了且它并没有解开,就会在这里一直等待下面的程序也没办法执行
print(123)
lock.release()
lock.release()
2. 死锁例子
- 吃面例子: 每个线程只有拿到筷子和面的时候才能吃上面
import time
from threading import Thread
from threading import Lock
kz = Lock() # 筷子锁
m = Lock() # 面锁
def eat1(name):
kz.acquire()
print('%s,拿到筷子了' % name)
m.acquire()
print('%s,拿到面' % name)
print('%s,吃面' % name)
m.release()
kz.release()
def eat2(name):
m.acquire()
print('%s,拿到面' % name)
time.sleep(1)
kz.acquire()
print('%s,拿到筷子了' % name)
print('%s,吃面' % name)
kz.release()
m.release()
Thread(target=eat1, args=('Kevin',)).start()
Thread(target=eat2, args=('Yeung',)).start()
Thread(target=eat1, args=('Jack',)).start()
Thread(target=eat2, args=('Amier',)).start()
# 执行结果
# Kevin,拿到筷子了
# Kevin,拿到面
# Kevin,吃面
# Yeung,拿到面
# Jack,拿到筷子了 -> 一直会在这里等待着,因为当Kevin吃完面后,Yeung拿到了面的钥匙,Jack拿到了筷子锁的钥匙,两个线程分别拿着不同的钥匙,而程序需要一个线程同时拿到两把钥匙才能执行下去
3. 递归锁 -> 递归锁是解决死锁的办法
- 进程中也有递归锁
- 第一次进入程序的时候无论程序上面执行了多少次acquire(),它都会往执行。
- 上面执行了 num 次 acquire() 上锁,程序下面就要执行 num 次 release() 解锁
- 使用递归锁解决多线程中死锁问题必须使用同一把递归锁
from threading import RLock
r_lock = RLock()
r_lock.acquire()
r_lock.acquire()
print(123)
r_lock.release()
r_lock.release()
4. 使用递归锁解决上面吃面例子的死锁问题
import time
from threading import Thread
from threading import RLock
m = kz = RLock() # 使用递归锁解决多线程中死锁问题必须是同一把锁,如果也是多把递归锁也是会出现死锁问题
def eat1(name):
kz.acquire()
print('%s,拿到筷子了' % name)
m.acquire()
print('%s,拿到面' % name)
print('%s,吃面' % name)
m.release()
kz.release()
def eat2(name):
m.acquire()
print('%s,拿到面' % name)
time.sleep(1)
kz.acquire()
print('%s,拿到筷子了' % name)
print('%s,吃面' % name)
kz.release()
m.release()
Thread(target=eat1, args=('Kevin',)).start()
Thread(target=eat2, args=('Yeung',)).start()
Thread(target=eat1, args=('Jack',)).start()
Thread(target=eat2, args=('Amier',)).start()